#pragma once

#include <initializer_list>
#include <string>
#include <sstream>
#include <vector>
#include <iterator>
#include <ctime>

namespace kratos {
namespace service {
    class ServiceContext;
}
}

namespace rpc {
    
class Rpc;

class RpcVersion {
    using VersionList = std::vector<std::string>;
    VersionList version_;
    using NumberList = std::vector<int>;
    NumberList numberList_;

public:
    using iterator = typename VersionList::iterator;
    using const_iterator = typename VersionList::const_iterator;
    using reverse_iterator = typename VersionList::reverse_iterator;
    using const_reverse_iterator = typename VersionList::const_reverse_iterator;

public:
    RpcVersion() {
        RpcVersion("1.0.0");
    }

    RpcVersion(const std::initializer_list<std::string>& version) {
        for (auto& v : version) {
            version_.push_back(v);
        }
    }

    RpcVersion(const std::string& version) {
        version_ = split(version, ".");
        for (auto& s : version_) {
            numberList_.push_back(std::stoi(s));
        }
    }

    RpcVersion(const RpcVersion& rht) {
        version_ = rht.version_;
        for (auto& s : version_) {
            numberList_.push_back(std::stoi(s));
        }
    }

    const RpcVersion& operator=(const RpcVersion& rht) {
        version_ = rht.version_;
        for (auto& s : version_) {
            numberList_.push_back(std::stoi(s));
        }
        return *this;
    }

    ~RpcVersion() {
    }

    std::size_t size() const {
        return version_.size();
    }

    bool empty() const {
        return version_.empty();
    }

    iterator begin() {
        return version_.begin();
    }

    iterator end() {
        return version_.end();
    }

    const_iterator begin() const {
        return version_.begin();
    }

    const_iterator end() const {
        return version_.end();
    }

    reverse_iterator rbegin() {
        return version_.rbegin();
    }

    reverse_iterator rend() {
        return version_.rend();
    }

    const_reverse_iterator rbegin() const {
        return version_.rbegin();
    }

    const_reverse_iterator rend() const {
        return version_.rend();
    }

    const std::string operator[](std::size_t index) {
        return version_[index];
    }

    bool operator<(const RpcVersion& rht) const {
        std::size_t i = 0;
        bool lesser = false;
        for (auto& n : numberList_) {
            if (i + 1 > rht.version_.size()) {
                return lesser;
            } else {
                if (n < rht.numberList_[i]) {
                    lesser = true;
                } else if (n == rht.numberList_[i]) {
                    i += 1;
                    continue;
                } else {
                    return false;
                }
            }
            i += 1;
        }
        return lesser;
    }

    bool operator>(const RpcVersion& rht) const {
        return !operator<(rht) && operator!=(rht);
    }

    bool operator==(const RpcVersion& rht) const {
        if (version_.size() != rht.version_.size()) {
            return false;
        }
        auto i = 0;
        for (auto& n : numberList_) {
            if (n != rht.numberList_[i]) {
                return false;
            }
            i += 1;
        }
        return true;
    }

    bool operator!=(const RpcVersion& rht) const {
        return !operator==(rht);
    }

    VersionList split(const std::string& in, const std::string& delim) {
        std::size_t end = 0;
        std::size_t begin = 0;
        std::string substr;
        VersionList list;
        while (end != std::string::npos) {
            end = in.find(delim, begin);
            if (end != std::string::npos) {
                substr = in.substr(begin, end - begin);
            } else {
                substr = in.substr(begin, std::string::npos);
            }
            if (!substr.empty() && (substr != delim)) {
                list.push_back(substr);
            }
            begin = end + delim.size();
        }
        return list;
    }
};

// RPC service interface
class RpcService {
    kratos::service::ServiceContext* ctx_{ nullptr };
public:
    // dtor
    virtual ~RpcService() {}
    // Invoked by framework after spawned
    virtual bool onAfterFork(rpc::Rpc* rpc) { return true; }
    // Invoked by framework before uninitialization
    virtual bool onBeforeDestory(rpc::Rpc* rpc) { return true; }
    // Tick
    virtual void onTick(std::time_t ms) { return;  }
    // Query context
    kratos::service::ServiceContext* getContext() {
        return ctx_;
    }
    // Setup context
    void setContext(kratos::service::ServiceContext* ctx) {
        ctx_ = ctx;
    }
};

}
